/* *
 *
 *  (c) 2010-2019 Torstein Honsi
 *
 *  License: www.highcharts.com/license
 *
 *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
 *
 * */
"use strict";
import H from "./Globals.js";
/**
 * A valid color to be parsed and handled by Highcharts. Highcharts internally
 * supports hex colors like `#ffffff`, rgb colors like `rgb(255,255,255)` and
 * rgba colors like `rgba(255,255,255,1)`. Other colors may be supported by the
 * browsers and displayed correctly, but Highcharts is not able to process them
 * and apply concepts like opacity and brightening.
 *
 * @typedef {string} Highcharts.ColorString
 */
/**
 * A valid color type than can be parsed and handled by Highcharts. It can be a
 * color string, a gradient object, or a pattern object.
 *
 * @typedef {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject} Highcharts.ColorType
 */
/**
 * Gradient options instead of a solid color.
 *
 * @example
 * // Linear gradient used as a color option
 * color: {
 *     linearGradient: { x1: 0, x2: 0, y1: 0, y2: 1 },
 *     stops: [
 *         [0, '#003399'], // start
 *         [0.5, '#ffffff'], // middle
 *         [1, '#3366AA'] // end
 *     ]
 * }
 *
 * @interface Highcharts.GradientColorObject
 */ /**
 * Holds an object that defines the start position and the end position relative
 * to the shape.
 * @name Highcharts.GradientColorObject#linearGradient
 * @type {Highcharts.LinearGradientColorObject|undefined}
 */ /**
 * Holds an object that defines the center position and the radius.
 * @name Highcharts.GradientColorObject#radialGradient
 * @type {Highcharts.RadialGradientColorObject|undefined}
 */ /**
 * The first item in each tuple is the position in the gradient, where 0 is the
 * start of the gradient and 1 is the end of the gradient. Multiple stops can be
 * applied. The second item is the color for each stop. This color can also be
 * given in the rgba format.
 * @name Highcharts.GradientColorObject#stops
 * @type {Array<Highcharts.GradientColorStopObject>}
 */
/**
 * Color stop tuple.
 *
 * @see Highcharts.GradientColorObject
 *
 * @interface Highcharts.GradientColorStopObject
 */ /**
 * @name Highcharts.GradientColorStopObject#0
 * @type {number}
 */ /**
 * @name Highcharts.GradientColorStopObject#1
 * @type {Highcharts.ColorString}
 */ /**
 * @name Highcharts.GradoentColorStopObject#color
 * @type {Highcharts.Color|undefined}
 */
/**
 * Defines the start position and the end position for a gradient relative
 * to the shape. Start position (x1, y1) and end position (x2, y2) are relative
 * to the shape, where 0 means top/left and 1 is bottom/right.
 *
 * @interface Highcharts.LinearGradientColorObject
 */ /**
 * Start horizontal position of the gradient. Float ranges 0-1.
 * @name Highcharts.LinearGradientColorObject#x1
 * @type {number}
 */ /**
 * End horizontal position of the gradient. Float ranges 0-1.
 * @name Highcharts.LinearGradientColorObject#x2
 * @type {number}
 */ /**
 * Start vertical position of the gradient. Float ranges 0-1.
 * @name Highcharts.LinearGradientColorObject#y1
 * @type {number}
 */ /**
 * End vertical position of the gradient. Float ranges 0-1.
 * @name Highcharts.LinearGradientColorObject#y2
 * @type {number}
 */
/**
 * Defines the center position and the radius for a gradient.
 *
 * @interface Highcharts.RadialGradientColorObject
 */ /**
 * Center horizontal position relative to the shape. Float ranges 0-1.
 * @name Highcharts.RadialGradientColorObject#cx
 * @type {number}
 */ /**
 * Center vertical position relative to the shape. Float ranges 0-1.
 * @name Highcharts.RadialGradientColorObject#cy
 * @type {number}
 */ /**
 * Radius relative to the shape. Float ranges 0-1.
 * @name Highcharts.RadialGradientColorObject#r
 * @type {number}
 */
import U from "./Utilities.js";
var isNumber = U.isNumber,
  pInt = U.pInt;
var merge = H.merge;
/* eslint-disable no-invalid-this, valid-jsdoc */
/**
 * Handle color operations. Some object methods are chainable.
 *
 * @class
 * @name Highcharts.Color
 *
 * @param {Highcharts.ColorType} input
 *        The input color in either rbga or hex format
 */
H.Color = function (input) {
  // Backwards compatibility, allow instanciation without new
  if (!(this instanceof H.Color)) {
    return new H.Color(input);
  }
  // Initialize
  this.init(input);
};
H.Color.prototype = {
  // Collection of parsers. This can be extended from the outside by pushing
  // parsers to Highcharts.Color.prototype.parsers.
  parsers: [
    {
      // RGBA color
      // eslint-disable-next-line max-len
      regex:
        /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]?(?:\.[0-9]+)?)\s*\)/,
      parse: function (result) {
        return [
          pInt(result[1]),
          pInt(result[2]),
          pInt(result[3]),
          parseFloat(result[4], 10),
        ];
      },
    },
    {
      // RGB color
      regex: /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/,
      parse: function (result) {
        return [pInt(result[1]), pInt(result[2]), pInt(result[3]), 1];
      },
    },
  ],
  // Collection of named colors. Can be extended from the outside by adding
  // colors to Highcharts.Color.prototype.names.
  names: {
    white: "#ffffff",
    black: "#000000",
  },
  /**
   * Parse the input color to rgba array
   *
   * @private
   * @function Highcharts.Color#init
   *
   * @param {Highcharts.ColorType} input
   *        The input color in either rbga or hex format
   *
   * @return {void}
   */
  init: function (input) {
    var result, rgba, i, parser, len;
    this.input = input =
      this.names[input && input.toLowerCase ? input.toLowerCase() : ""] ||
      input;
    // Gradients
    if (input && input.stops) {
      this.stops = input.stops.map(function (stop) {
        return new H.Color(stop[1]);
      });
      // Solid colors
    } else {
      // Bitmasking as input[0] is not working for legacy IE.
      if (input && input.charAt && input.charAt() === "#") {
        len = input.length;
        input = parseInt(input.substr(1), 16);
        // Handle long-form, e.g. #AABBCC
        if (len === 7) {
          rgba = [
            (input & 0xff0000) >> 16,
            (input & 0xff00) >> 8,
            input & 0xff,
            1,
          ];
          // Handle short-form, e.g. #ABC
          // In short form, the value is assumed to be the same
          // for both nibbles for each component. e.g. #ABC = #AABBCC
        } else if (len === 4) {
          rgba = [
            ((input & 0xf00) >> 4) | ((input & 0xf00) >> 8),
            ((input & 0xf0) >> 4) | (input & 0xf0),
            ((input & 0xf) << 4) | (input & 0xf),
            1,
          ];
        }
      }
      // Otherwise, check regex parsers
      if (!rgba) {
        i = this.parsers.length;
        while (i-- && !rgba) {
          parser = this.parsers[i];
          result = parser.regex.exec(input);
          if (result) {
            rgba = parser.parse(result);
          }
        }
      }
    }
    this.rgba = rgba || [];
  },
  /**
   * Return the color or gradient stops in the specified format
   *
   * @function Highcharts.Color#get
   *
   * @param {string} [format]
   *        Possible values are 'a', 'rgb', 'rgba' (default).
   *
   * @return {Highcharts.ColorType}
   *         This color as a string or gradient stops.
   */
  get: function (format) {
    var input = this.input,
      rgba = this.rgba,
      ret;
    if (this.stops) {
      ret = merge(input);
      ret.stops = [].concat(ret.stops);
      this.stops.forEach(function (stop, i) {
        ret.stops[i] = [ret.stops[i][0], stop.get(format)];
      });
      // it's NaN if gradient colors on a column chart
    } else if (rgba && isNumber(rgba[0])) {
      if (format === "rgb" || (!format && rgba[3] === 1)) {
        ret = "rgb(" + rgba[0] + "," + rgba[1] + "," + rgba[2] + ")";
      } else if (format === "a") {
        ret = rgba[3];
      } else {
        ret = "rgba(" + rgba.join(",") + ")";
      }
    } else {
      ret = input;
    }
    return ret;
  },
  /**
   * Brighten the color instance.
   *
   * @function Highcharts.Color#brighten
   *
   * @param {number} alpha
   *        The alpha value.
   *
   * @return {Highcharts.Color}
   *         This color with modifications.
   */
  brighten: function (alpha) {
    var i,
      rgba = this.rgba;
    if (this.stops) {
      this.stops.forEach(function (stop) {
        stop.brighten(alpha);
      });
    } else if (isNumber(alpha) && alpha !== 0) {
      for (i = 0; i < 3; i++) {
        rgba[i] += pInt(alpha * 255);
        if (rgba[i] < 0) {
          rgba[i] = 0;
        }
        if (rgba[i] > 255) {
          rgba[i] = 255;
        }
      }
    }
    return this;
  },
  /**
   * Set the color's opacity to a given alpha value.
   *
   * @function Highcharts.Color#setOpacity
   *
   * @param {number} alpha
   *        Opacity between 0 and 1.
   *
   * @return {Highcharts.Color}
   *         Color with modifications.
   */
  setOpacity: function (alpha) {
    this.rgba[3] = alpha;
    return this;
  },
  /**
   * Return an intermediate color between two colors.
   *
   * @function Highcharts.Color#tweenTo
   *
   * @param {Highcharts.Color} to
   *        The color object to tween to.
   *
   * @param {number} pos
   *        The intermediate position, where 0 is the from color (current
   *        color item), and 1 is the `to` color.
   *
   * @return {Highcharts.ColorString}
   *         The intermediate color in rgba notation.
   */
  tweenTo: function (to, pos) {
    // Check for has alpha, because rgba colors perform worse due to lack of
    // support in WebKit.
    var fromRgba = this.rgba,
      toRgba = to.rgba,
      hasAlpha,
      ret;
    // Unsupported color, return to-color (#3920, #7034)
    if (!toRgba.length || !fromRgba || !fromRgba.length) {
      ret = to.input || "none";
      // Interpolate
    } else {
      hasAlpha = toRgba[3] !== 1 || fromRgba[3] !== 1;
      ret =
        (hasAlpha ? "rgba(" : "rgb(") +
        Math.round(toRgba[0] + (fromRgba[0] - toRgba[0]) * (1 - pos)) +
        "," +
        Math.round(toRgba[1] + (fromRgba[1] - toRgba[1]) * (1 - pos)) +
        "," +
        Math.round(toRgba[2] + (fromRgba[2] - toRgba[2]) * (1 - pos)) +
        (hasAlpha
          ? "," + (toRgba[3] + (fromRgba[3] - toRgba[3]) * (1 - pos))
          : "") +
        ")";
    }
    return ret;
  },
};
/**
 * Creates a color instance out of a color string.
 *
 * @function Highcharts.color
 *
 * @param {Highcharts.ColorType} input
 *        The input color in either rbga or hex format
 *
 * @return {Highcharts.Color}
 *         Color instance
 */
H.color = function (input) {
  return new H.Color(input);
};
